﻿/**
 * Copyright (C) 2012-2013 original author and authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NGuice.Inject.Internal.Util;
using NGuice.Inject.Spi;

namespace NGuice.Inject.Internal
{
    /// <summary>
    /// 委托到一个自定义工厂，此自定义工厂在注入器中绑定
    /// </summary>
    internal sealed class BoundProviderFactory<T> : InternalFactory<T>
    {
        private readonly InjectorImpl injector;
        readonly Key providerKey;//泛型参数必须为IProvider<T>子类
        readonly object source;
        private InternalFactory providerFactory;//泛型参数必须为IProvider<T>子类

        public BoundProviderFactory(InjectorImpl injector, Key providerKey, object source)
        {
            Preconditions.CheckSubGenericParameter<IProvider<T>>(providerKey);
            this.injector = injector;
            this.providerKey = providerKey;
            this.source = source;
        }

        public T Get(Errors errors, InternalContext context, Dependency dependency, bool linked)
        {
            errors = errors.WithSource(providerKey);
            IProvider<T> provider = (IProvider<T>)providerFactory.Get(errors, context, dependency, true);
            try
            {
                return errors.CheckForNull(provider.Get(), source, dependency);
            }
            catch (Exception userException)
            {
                throw errors.ErrorInProvider(userException).ToException();
            }
        }

        /// <summary>
        /// BindingProcessor中CreationNotify委托的方法
        /// </summary>
        /// <param name="errors"></param>
        public void Notify(Errors errors)
        {
            try
            {
                providerFactory = injector.GetInternalFactory(providerKey, errors.WithSource(source), InjectorImpl.JitLimitation.NEW_OR_EXISTING_JIT);
            }
            catch (ErrorsException e)
            {
                errors.Merge(e.Errors);
            }
        }

        public string ToString()
        {
            return providerKey.ToString();
        }

        object InternalFactory.Get(Errors errors, InternalContext context, Dependency dependency, bool linked)
        {
            return Get(errors, context, dependency, linked);
        }
    }
}
